#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Copyright (c) 61DUke.

# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Readme Document for more details.
# Create: 2020-12-27

import imageio
import numpy as np
from PIL import Image

__all__ = ["stitch_images2gif", "stitch_images"]


def stitch_images2gif(source_images_path: list,
                      output_path: str
                      ):
    """
    Convert static picture to GIF moving picture

    :param source_images_path:
    :param output_path:
    :return:

    Example:
    ---------
        >>> stitch_images2gif(
        ...     source_images_path=[],
        ...     output_path=""
        ... )
    """
    if not isinstance(source_images_path, list) or not source_images_path:
        raise ValueError("source_image_path param type must list!")
    if not isinstance(output_path, str) or not output_path:
        raise ValueError("output_path param type must string!")

    gif_images = [imageio.imread(image_path) for image_path in source_images_path]
    return imageio.mimsave(output_path, gif_images, fps=30)


def stitch_images(source_images_path: list,
                  output_path: str,
                  layout: tuple,
                  each_image_shape=(0, 0)
                  ):
    """
    Image arbitrary splicing, parametric form code

    :param source_images_path:

    :param output_path:

    :param layout: tuple type,
        (
            picture interval, that is, how many lines are there after merging into a picture,
            picture interval, that is, how many columns are there after merging into a picture
        )
    :param each_image_shape: tuple type, picture size
    :return:

    Functions:
    ---------
        Modify the value of the constant to realize different image stitching,
        such as stitching into 5 * 20 or 100 * 200
        large images, and each small image can also be controlled in size

    Example:
    ---------
    >>> stitch_images(
    >>>     source_images_path=[
    ...         "imgs/20191017185607410.png",
    ...         "imgs/20191017185634484.png",
    ...         "imgs/icon.jpg",
    ...         "imgs/IMG_2229.JPG",
    ...         "imgs/IMG_2994.JPG"
    ...     ],
    ...     output_path="output.png",
    ...     layout=(4, 2),
    ...     each_image_shape=(0, 0)
    ... )

    """
    if not isinstance(source_images_path, list) or not len(source_images_path):
        raise ValueError("source_images_path param type must list!")
    if not isinstance(output_path, str) or not len(output_path):
        raise ValueError("output_path param type must string!")
    if not isinstance(layout, tuple) or len(layout) != 2:
        raise ValueError("layout param type must 2-tuple!")
    if not isinstance(each_image_shape, tuple) or len(each_image_shape) != 2:
        raise ValueError("each_image_shape param type must 2-tuple!")

    images = list(map(lambda img: Image.open(img), source_images_path))

    row_num, column_num = layout
    if row_num == 0 and column_num != 0:
        row_num = np.ceil(len(images) / column_num)
    elif row_num != 0 and column_num == 0:
        column_num = np.ceil(len(images) / row_num)
    elif row_num == 0 and column_num == 0:
        column_num = 1
        row_num = np.ceil(len(images) / column_num)
    elif row_num < 0 or column_num < 0:
        raise ValueError("Why? layout params have <0 value, Sick!")
    else:
        # Stitching according to his specified layout
        if row_num * column_num < len(images) or row_num * column_num > len(images):
            row_num = np.ceil(len(images) / column_num)

    row_size, column_size = each_image_shape
    if row_size == 0 and column_size != 0:
        row_size = np.ceil(np.mean(list(map(lambda img: img.size[0], images))))
    elif row_size != 0 and column_size == 0:
        column_size = np.ceil(np.mean(list(map(lambda img: img.size[1], images))))
    elif row_size == 0 and column_size == 0:
        row_size = np.ceil(np.mean(list(map(lambda img: img.size[0], images))))
        column_size = np.ceil(np.mean(list(map(lambda img: img.size[1], images))))
    elif row_size < 0 or column_size < 0:
        raise ValueError("Why? each_image_shape params have <0 value, Sick!")
    row_num, column_num, row_size, column_size = map(int, [row_num, column_num, row_size, column_size])

    stitch_image = Image.new('RGB', (column_num * row_size, row_num * column_size))

    # Loop traversal, paste each picture to the corresponding position in order
    paste_count = 0
    for y in range(1, row_num + 1):
        for x in range(1, column_num + 1):
            from_image = images[column_num * (y - 1) + x - 1].resize((row_size, column_size), Image.ANTIALIAS)
            stitch_image.paste(from_image, ((x - 1) * row_size, (y - 1) * column_size))
            paste_count += 1
            if paste_count == len(images):
                break
    # Save new map
    return stitch_image.save(output_path)


if __name__ == '__main__':
    pass



